<pre class='metadata'>
Title: CSS Nesting Module Level 1
Shortname: css-nesting
Level: 1
Status: ED
Work Status: Exploring
Group: CSSWG
ED: https://drafts.csswg.org/css-nesting/
TR: https://www.w3.org/TR/css-nesting-1/
Editor: Tab Atkins-Bittner, Google, http://xanthir.com/contact/, w3cid 42199
Former Editor: Adam Argyle, Google, https://nerdy.dev, w3cid 112669
Abstract: This module introduces the ability to nest one style rule inside another, with the selector of the child rule relative to the selector of the parent rule.  This increases the modularity and maintainability of CSS stylesheets.
Default Highlight: css
Include MDN Panels: no
</pre>

<pre class=link-defaults>
spec:css-color-4; type:property; text:color
spec:css-values-4; type:dfn; text:identifier
spec:cssom-1; type:dfn;
	text:child css rules
	text:specified order
spec:selectors-4; type:dfn;
	text: combinators
	text: simple selector
	text: type selector
</pre>

<h2 id="intro">
Introduction</h2>

	<em>This section is not normative.</em>

	This module describes support for nesting a style rule within another style rule,
	allowing the inner rule's selector to reference the elements matched by the outer rule.
	This feature allows related styles to be aggregated into a single structure within the CSS document,
	improving readability and maintainability.

<h3 id="placement">
Module Interactions</h3>

	This module introduces new parser rules that extend the [[!CSS21]] parser model.
	It introduces selectors that extend the [[SELECTORS-4]] module.
	It extends and modifies some IDL and algorithms defined in the [[CSSOM-1]] module.

<h3 id="values">
Values</h3>

	This specification does not define any new properties or values.

<h2 id="explainer">
Explainer</h2>

	<em>This section is non-normative.</em>

	Imagine you have some CSS that you’d like to write in a more compact way.

	<pre>
	.foo {
		color: green;
	}
	.foo .bar {
		font-size: 1.4rem;
	}
	</pre>

	With Nesting, you can write such code as:

	<pre>
	.foo {
		color: green;
		.bar {
			font-size: 1.4rem;
		}
	}
	</pre>

	If you’ve been nesting styles in Sass
	or other CSS preprocessors,
	you will find this very familiar.

	You can nest any rules inside of a parent style rule:

	<pre>
	main {
		div { ... }
		.bar { ... }
		#baz { ...}
		:has(p) { ... }
		::backdrop { ... }
		[lang|="zh"] { ... }
		* { ... }
	}
	</pre>

	By default, the child rule's selector
	is assumed to connect to the parent rule
	by a [=descendant combinator=],
	but you can start the nested selector
	with any combinator to change that:

	<pre>
	main {
		+ article { ... }
		> p { ... }
		~ main { ... }
	}
	</pre>

	The new ''&'' selector lets you refer to
	the elements matched by the parent selector explictly,
	so the previous examples could have been written as:

	<pre>
	main {
		& + article { ... }
		& > p { ... }
		& ~ main { ... }
	}
	</pre>

	But you can place the ''&'' in other locations
	within the nested selector,
	to indicate other types of relationships
	between the parent and child rule.
	For example,
	this CSS:

	<pre>
	ul {
		padding-left: 1em;
	}
	.component ul {
		padding-left: 0;
	}
	</pre>

	Can be rewritten using Nesting as:

	<pre>
	ul {
		padding-left: 1em;
		.component & {
			padding-left: 0;
		}
	}
	</pre>

	Again, the ''&'' gives you a way to say
	“this is where I want the nested selector to go”.

	It’s also handy when you don’t want a space between your selectors.
	For example:

	<pre>
	a {
		color: blue;
		&:hover {
			color: lightblue;
		}
	}
	</pre>

	Such code yields the same result as <code>a:hover {</code>.
	Without the ''&'',
	you’d get <code>a :hover {</code>--
	notice the space between <code>a</code> and <code>:hover</code>--
	which would fail to style your hover link.

	You can nest more than one layer deep--
	nesting CSS inside already-nested CSS--
	in as many levels as you desire.
	You can mix Nesting with
	Container Queries, Supports Queries, Media Queries, and/or Cascade Layers
	however you want.
	(Nearly) anything can go inside of anything.

Nesting Style Rules {#nesting}
==============================

	Style rules can be nested inside of other styles rules.
	These <dfn export lt="nested style rule|nesting style rule">nested style rules</dfn>
	act exactly like ordinary style rules--
	associating properties with elements via selectors--
	but they "inherit" their parent rule's selector context,
	allowing them to further build on the parent's selector
	without having to repeat it,
	possibly multiple times.

	A [=nested style rule=] is exactly like a normal style rule,
	except that it can use [=relative selectors=],
	which are implicitly relative
	to the elements matched by the parent rule.

	<div class=example>
		That is,
		a nested style rule like:

		<pre class=lang-css>
		.foo {
			color: red;

			a {
				color: blue;
			}
		}
		</pre>

		is valid,
		and equivalent to:

		<pre class=lang-css>
		.foo {
			color: red;
		}
		.foo a {
			color: blue;
		}
		</pre>

		The nested rule can also use the [=nesting selector=]
		to directly refer to the parent rule's matched elements,
		or use [=relative selector=] syntax
		to specify relationships other than "descendant".

		<pre class=lang-css>
		.foo {
			color: red;

			&:hover {
				color: blue;
			}
		}

		/* equivalent to: */

		.foo { color: red; }
		.foo:hover { color: blue; }
		</pre>

		<pre class=lang-css>
		.foo {
			color: red;

			+ .bar {
				color: blue;
			}
		}

		/* equivalent to: */

		.foo { color: red; }
		.foo + .bar { color: blue; }
		</pre>
	</div>


<!-- Big Text: syntax

 ███▌  █   ▐▌ █    █▌ █████▌  ███▌  █     █
█▌  █▌ ▐▌  █  █▌   █▌   █▌   ▐█ ▐█   █   █
█▌      █ ▐▌  ██▌  █▌   █▌   █▌  █▌   █ █
 ███▌   ▐▌█   █▌▐█ █▌   █▌   █▌  █▌    █
    █▌   █▌   █▌  ██▌   █▌   █████▌   █ █
█▌  █▌   █▌   █▌   █▌   █▌   █▌  █▌  █   █
 ███▌    █▌   █▌   ▐▌   █▌   █▌  █▌ █     █
-->

Syntax {#syntax}
------------------------

	The contents of [=style rules=]
	now accepts [=nested style rules=]
	and [=at-rules=],
	in addition to the existing [=declarations=].

	[=Nested style rules=] differ from non-nested rules
	in the following ways:

	* A [=nested style rule=] accepts a <<relative-selector-list>>
		as its prelude
		(rather than just a <<selector-list>>).
		Any [=relative selectors=]
		are relative to the elements represented by the [=nesting selector=].
	* If a selector in the <<relative-selector-list>>
		does not start with a [=combinator=]
		but does [=contain the nesting selector=],
		it is interpreted as a non-[=relative selector=].

	The precise details of how nested style rules are parsed
	are defined in [[!CSS-SYNTAX-3]].

	An invalid [=nested style rule=] is ignored,
	along with its contents,
	but does not invalidate its parent rule.

	Nested rules with [=relative selectors=]
	include the specificity of their implied [=nesting selector=].
	For example, ''.foo { > .bar {...}}'' and ''.foo { & > .bar {...}}''
	have the same specificity for their inner rule.

	<div class=note>
		Some CSS-generating tools that preprocess nesting
		will concatenate selectors as strings,
		allowing authors to build up a <em>single</em> [=simple selector=]
		across nesting levels.
		This is sometimes used with hierarchical name patterns
		like <a href="https://en.wikipedia.org/wiki/CSS#:~:text=bem%20(block%2C%20element%2C%20modifier)">BEM</a>
		to reduce repetition across a file,
		when the selectors themselves have significant repetition internally.

		For example, if one component uses the class ''.foo'',
		and a nested component uses ''.fooBar'',
		you could write this in <a href="https://sass-lang.com/">Sass</a> as:

		<xmp class="lang-css">
		.foo {
			color: blue;
			&Bar { color: red; }
		}
		/* In Sass, this is equivalent to
			.foo { color: blue; }
			.fooBar { color: red; }
		*/
		</xmp>

		This is not allowed in CSS,
		as nesting is not a syntax transformation,
		but rather matches on the actual elements the parent selector matches.

		It is also true that the selector ''&amp;Bar'' is invalid in CSS in the first place,
		as the ''Bar'' part is a type selector,
		which must come first in the compound selector.
		(That is, it must be written as ''Bar&amp;''.)
		So, luckily, there is no overlap between CSS Nesting
		and the preprocessor syntax.
	</div>

	<div algorithm>
		A selector is said to <dfn export>contain the nesting selector</dfn>
		if, when it was [=CSS/parsed=] as any type of selector,
		a <<delim-token>> with the value "&" (U+0026 AMPERSAND) was encountered.

		Note: This is phrased in this explicit manner
		so as to catch cases like '':is(:unknown(&), .bar)'',
		where an unknown selector
		(which, being unknown, we have no way of knowing
		whether the argument is <em>meant</em> to be parsed as a selector or not)
		is the only part of the selector that contains an ''&''.
		As that <em>might</em> be a perfectly valid selector
		that's only supported by newer browsers,
		and we don't want parsing to be dependent on unrelated versioning issues,
		we treat it as still [=containing the nesting selector=].
	</div>

	If a <<forgiving-selector-list>> has an item that [=contains the nesting selector=]
	but is invalid,
	that item is preserved exactly as-is
	rather than being discarded.
	(This does not change the matching behavior of the selector--
	an invalid selector still fails to match anything--
	just the serialization of the selector.)

	Issue: The preceding paragraph needs to move to Selectors
	when we move ''&'' itself to Selectors;
	I'm monkey-patching for convenience here.

<!-- Big Text: example

█████▌ █     █  ███▌  █     █ ████▌  █▌    █████▌
█▌      █   █  ▐█ ▐█  ██   ██ █▌  █▌ █▌    █▌
█▌       █ █   █▌  █▌ █▌█ █▐█ █▌  █▌ █▌    █▌
████      █    █▌  █▌ █▌ █ ▐█ ████▌  █▌    ████
█▌       █ █   █████▌ █▌   ▐█ █▌     █▌    █▌
█▌      █   █  █▌  █▌ █▌   ▐█ █▌     █▌    █▌
█████▌ █     █ █▌  █▌ █▌   ▐█ █▌     █████ █████▌
-->

<h3 id=syntax-examples>
Examples</h3>

	<pre class=lang-css>
	<b>/* & can be used on its own */</b>
	.foo {
		color: blue;
		& > .bar { color: red; }
		> .baz { color: green; }
	}
	/* equivalent to
		.foo { color: blue; }
		.foo > .bar { color: red; }
		.foo > .baz { color: green; }
	*/


	<b>/* or in a compound selector,
	   refining the parent's selector */</b>
	.foo {
		color: blue;
		&.bar { color: red; }
	}
	/* equivalent to
		.foo { color: blue; }
		.foo.bar { color: red; }
	*/

	<b>/* multiple selectors in the list are all
	   relative to the parent */</b>
	.foo, .bar {
		color: blue;
		+ .baz, &.qux { color: red; }
	}
	/* equivalent to
		.foo, .bar { color: blue; }
		:is(.foo, .bar) + .baz,
		:is(.foo, .bar).qux { color: red; }
	*/

	<b>/* & can be used multiple times in a single selector */</b>
	.foo {
		color: blue;
		& .bar & .baz & .qux { color: red; }
	}
	/* equivalent to
		.foo { color: blue; }
		.foo .bar .foo .baz .foo .qux { color: red; }
	*/

	<b>/* & doesn't have to be at the beginning of the selector */</b>

	.foo {
		color: red;
		.parent & {
			color: blue;
		}
	}
	/* equivalent to
		.foo { color: red; }
		.parent .foo { color: blue; }
	*/

	.foo {
		color: red;
		:not(&) {
			color: blue;
		}
	}
	/* equivalent to
		.foo { color: red; }
		:not(.foo) { color: blue; }
	*/

	<b>/* But if you use a <l>[=relative selector=]</l>,
		an initial & is implied automatically */</b>

	.foo {
		color: red;
		+ .bar + & { color: blue; }
	}

	/* equivalent to
		.foo { color: red; }
		.foo + .bar + .foo { color: blue; }
	*/

	<b>/* Somewhat silly, but & can be used all on its own, as well. */</b>
	.foo {
		color: blue;
		& { padding: 2ch; }
	}
	/* equivalent to
		.foo { color: blue; }
		.foo { padding: 2ch; }

		// or

		.foo {
			color: blue;
			padding: 2ch;
		}
	*/

	<b>/* Again, silly, but can even be doubled up. */</b>
	.foo {
		color: blue;
		&& { padding: 2ch; }
	}
	/* equivalent to
		.foo { color: blue; }
		.foo.foo { padding: 2ch; }
	*/

	<b>/* The parent selector can be arbitrarily complicated */</b>
	.error, #404 {
		&:hover > .baz { color: red; }
	}
	/* equivalent to
		:is(.error, #404):hover > .baz { color: red; }
	*/

	.ancestor .el {
		.other-ancestor & { color: red; }
	}
	/* equivalent to
		.other-ancestor :is(.ancestor .el) { color: red; }

	<b>/* As can the nested selector */</b>
	.foo {
		& :is(.bar, &.baz) { color: red; }
	}
	/* equivalent to
		.foo :is(.bar, .foo.baz) { color: red; }
	*/

	<b>/* Multiple levels of nesting "stack up" the selectors */</b>
	figure {
		margin: 0;

		> figcaption {
			background: hsl(0 0% 0% / 50%);

			> p {
				font-size: .9rem;
			}
		}
	}
	/* equivalent to
		figure { margin: 0; }
		figure > figcaption { background: hsl(0 0% 0% / 50%); }
		figure > figcaption > p { font-size: .9rem; }
	*/

	<b>/* Example usage with Cascade Layers */</b>
	@layer base {
		html {
			block-size: 100%;

			body {
				min-block-size: 100%;
			}
		}
	}
	/* equivalent to
		@layer base {
			html { block-size: 100%; }
			html body { min-block-size: 100%; }
		}
	*/

	<b>/* Example nesting Cascade Layers */</b>
	@layer base {
	  html {
			block-size: 100%;

			@layer support {
				body {
					min-block-size: 100%;
				}
			}
		}
	}
	/* equivalent to
		@layer base {
			html { block-size: 100%; }
		}
		@layer base.support {
			html body { min-block-size: 100%; }
		}
	*/

	<b>/* Example usage with Scoping */</b>
	@scope (.card) to (> header) {
	  :scope {
			inline-size: 40ch;
			aspect-ratio: 3/4;

			> header {
				border-block-end: 1px solid white;
			}
		}
	}
	/* equivalent to
		@scope (.card) to (> header) {
			:scope { inline-size: 40ch; aspect-ratio: 3/4; }
			:scope > header { border-block-end: 1px solid white; }
		}
	*/

	<b>/* Example nesting Scoping */</b>
	.card {
		inline-size: 40ch;
		aspect-ratio: 3/4;

		@scope (&) to (> header > *) {
			:scope > header {
				border-block-end: 1px solid white;
			}
		}
	}

	/* equivalent to
		.card { inline-size: 40ch; aspect-ratio: 3/4; }
		@scope (.card) to (> header > *) {
			:scope > header { border-block-end: 1px solid white; }
		}
	*/
	</pre>



<!-- Big Text: group

 ███▌  ████▌   ███▌  █▌  █▌ ████▌
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌
█▌     █▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌
█▌ ██▌ ████▌  █▌  █▌ █▌  █▌ ████▌
█▌  █▌ █▌▐█   █▌  █▌ █▌  █▌ █▌
█▌  █▌ █▌ ▐█  █▌  █▌ █▌  █▌ █▌
 ███▌  █▌  █▌  ███▌   ███▌  █▌
-->

Nesting Other At-Rules {#conditionals}
--------------------------------------

	In addition to [=nested style rules=],
	this specification allows <dfn export>nested group rules</dfn>
	inside of [=style rules=]:
	any at-rule whose body contains [=style rules=]
	can be nested inside of a [=style rule=] as well,
	unless otherwise specified.

	When nested in this way,
	the contents of a [=nested group rule=]'s block
	are parsed as <<block-contents>>
	rather than <<rule-list>>:

	* [=Style rules=] are [=nested style rules=],
		with their [=nesting selector=] taking its definition
		from the nearest ancestor [=style rule=].
	* Properties can be directly used,
		acting as if they were nested in a [=nested declarations rule=].

	<div class=note>
		Specifically, these rules are capable of being [=nested group rules=]:

		* all the [=conditional group rules=] (''@container'', ''@media'', ''@supports'')
		* ''@layer''
		* ''@scope''
	</div>

	The meanings and behavior of such [=nested group rules=]
	is otherwise unchanged,
	unless otherwise specified.

	<div class="example">
		For example, the following conditional nestings are valid:

		<pre class="lang-css">
		<b>/* Properties can be directly used */</b>
		.foo {
			display: grid;

			@media (orientation: landscape) {
				grid-auto-flow: column;
			}
		}

		/* equivalent to: */
		.foo {
			display: grid;
		}
		@media (orientation: landscape) {
			.foo {
				grid-auto-flow: column
			}
		}

		/* and also equivalent to the unnested: */
		.foo { display: grid; }

		@media (orientation: landscape) {
			.foo {
				grid-auto-flow: column;
			}
		}

		<b>/* Conditionals can be further nested */</b>
		.foo {
			display: grid;

			@media (orientation: landscape) {
				grid-auto-flow: column;

				@media (min-width > 1024px) {
					max-inline-size: 1024px;
				}
			}
		}

		/* equivalent to */
		.foo { display: grid; }

		@media (orientation: landscape) {
			.foo {
				grid-auto-flow: column;
			}
		}

		@media (orientation: landscape) and (min-width > 1024px) {
			.foo {
				max-inline-size: 1024px;
			}
		}

		<b>/* Example nesting Cascade Layers */</b>
		html {
			@layer base {
				block-size: 100%;

				@layer support {
					& body {
						min-block-size: 100%;
					}
				}
			}
		}

		/* equivalent to */
		@layer base {
			html { block-size: 100%; }
		}
		@layer base.support {
			html body { min-block-size: 100%; }
		}

		<b>/* Example nesting Scoping */</b>
		.card {
			inline-size: 40ch;
			aspect-ratio: 3/4;

			@scope (&) {
				:scope {
					border: 1px solid white;
				}
			}
		}

		/* equivalent to */
		.card { inline-size: 40ch; aspect-ratio: 3/4; }
		@scope (.card) {
			:scope { border-block-end: 1px solid white; }
		}
		</pre>
	</div>

	Runs of consecutive directly-nested properties
	are automatically wrapped in [=nested declarations rules=].
	(This is observable in the CSSOM.)

<h4 id=nesting-at-scope>
Nested ''@scope'' Rules</h4>

	When the ''@scope'' rule is a [=nested group rule=],
	an ''&'' in the <<scope-start>> selector
	refers to the elements matched
	by the nearest ancestor style rule.

	<div class=example>
		That is, the following code:

		<pre highlight=css>
		.parent {
			color: blue;

			@scope (& > .scope) to (& .limit) {
				& .content {
					color: red;
				}
			}
		}
		</pre>

		is equivalent to:

		<pre highlight=css>
		.parent { color: blue; }
		@scope (.parent > .scope) to (:where(:scope) .limit) {
			:where(:scope) .content {
				color: red;
			}
		}
		</pre>
	</div>

	<div class=note>
	The ''&'' selector behaves like <code>:where(:scope)</code>
	in ''@scope'' rules.
	</div>

<!-- Big Text: mixing

█     █ ████ █     █ ████ █    █▌  ███▌
██   ██  ▐▌   █   █   ▐▌  █▌   █▌ █▌  █▌
█▌█ █▐█  ▐▌    █ █    ▐▌  ██▌  █▌ █▌
█▌ █ ▐█  ▐▌     █     ▐▌  █▌▐█ █▌ █▌ ██▌
█▌   ▐█  ▐▌    █ █    ▐▌  █▌  ██▌ █▌  █▌
█▌   ▐█  ▐▌   █   █   ▐▌  █▌   █▌ █▌  █▌
█▌   ▐█ ████ █     █ ████ █▌   ▐▌  ███▌
-->

Mixing Nesting Rules and Declarations {#mixing}
-----------------------------------------------

	When a style rule contains both declarations
	and [=nested style rules=] or [=nested group rules=],
	all three can be arbitrarily mixed.
	Declarations coming after or between rules
	are implicitly wrapped in [=nested declarations rules=],
	to preserve their order relative to the other rules.

	<div class=example>
		For example,
		in the following code:

		<pre class=lang-css>
		article {
			color: green;
			& { color: blue; }
			color: red;
		}

		/* equivalent to */
		article { color: green; }
		:is(article) { color: blue; }
		article { color: red; }

		/* NOT equivalent to */
		article { color: green; }
		article { color: red; }
		:is(article) { color: blue; }
		</pre>
	</div>

	For the purpose of determining the [[css-cascade-4#cascade-sort|Order Of Appearance]],
	[=nested style rules=] and [=nested group rules=]
	are considered to come <em>after</em> their parent rule.

	<div>
		For example:

		<xmp class=lang-css>
			article {
				color: blue;
				& { color: red; }
			}
		</xmp>

		Both declarations have the same specificity (0,0,1),
		but the nested rule is considered to come <em>after</em> its parent rule,
		so the ''color: red'' declarations wins the cascade.

		On the other hand, in this example:

		<xmp class=lang-css>
			article {
				color: blue;
				:where(&) { color: red; }
			}
		</xmp>

		The '':where()'' pseudoclass reduces the specificity of the [=nesting selector=] to 0,
		so the ''color: red'' declaration now has a specificity of (0,0,0),
		and loses to the ''color: blue'' declaration
		before "Order Of Appearance" comes into consideration.
	</div>

	Note: While one <em>can</em> freely intermix declarations and nested rules,
	it's harder to read and somewhat confusing to do so,
	since the later properties are automatically wrapped in a [=nested declarations rule=]
	that doesn't appear in the source text.
	For readability's sake,
	it's recommended that authors put all their properties first in a style rule,
	before any nested rules.
	(This also happens to act slightly better in older user agents:
	due to specifics of how parsing and error-recovery work,
	properties appearing after nested rules can get skipped.)


<!-- Big Text: &

  ███▌
 █▌  █▌
  █▌█▌
 ███▌
█▌  █  █▌
█▌   ██

-->

Nesting Selector: the ''&'' selector {#nest-selector}
=====================================================

	When using a <a>nested style rule</a>,
	one must be able to refer to the elements matched by the parent rule;
	that is, after all, <em>the entire point of nesting</em>.
	To accomplish that,
	this specification defines a new selector,
	the <dfn export>nesting selector</dfn>,
	written as <dfn selector>&</dfn> (U+0026 AMPERSAND).

	When used in the selector of a <a>nested style rule</a>,
	the <a>nesting selector</a> represents the elements matched by the parent rule.
	When used in any other context,
	it represents the same elements as '':scope'' in that context
	(unless otherwise defined).

	<div class="note">
		The <a>nesting selector</a> can be desugared
		by replacing it with the parent style rule's selector,
		wrapped in an '':is()'' selector.
		For example,

		<pre class=lang-css>
		a, b {
			& c { color: blue; }
		}
		</pre>

		is equivalent to

		<pre class=lang-css>
		:is(a, b) c { color: blue; }
		</pre>
	</div>

	The [=nesting selector=] cannot represent pseudo-elements
	(identical to the behavior of the '':is()'' pseudo-class).

	<div class=example>
		For example, in the following style rule:

		<pre class=lang-css>
		.foo, .foo::before, .foo::after {
			color: red;

			&:hover { color: blue; }
		}
		</pre>

		the ''&'' only represents the elements matched by ''.foo'';
		in other words, it's equivalent to:

		<pre class=lang-css>
		.foo, .foo::before, .foo::after {
			color: red;
		}
		.foo:hover {
			color: blue;
		}
		</pre>
	</div>

	Issue: We'd like to relax this restriction,
	but need to do so simultaneously for both '':is()'' and ''&'',
	since they're intentionally built on the same underlying mechanisms.
	(<a href="https://github.com/w3c/csswg-drafts/issues/7433">Issue 7433</a>)

	The <a>specificity</a> of the <a>nesting selector</a>
	is equal to the largest specificity among the complex selectors
	in the parent style rule's selector list
	(identical to the behavior of '':is()''),
	or zero if no such selector list exists.

	<div class="example">
		For example, given the following style rules:

		<pre class=lang-css>
		#a, b {
			& c { color: blue; }
		}
		.foo c { color: red; }
		</pre>

		Then in a DOM structure like

		<xmp class="lang-html">
			<b class=foo>
				<c>Blue text</c>
			</b>
		</xmp>

		The text will be blue, rather than red.
		The specificity of the ''&''
		is the larger of the specificities of ''#a'' ([1,0,0])
		and <css>b</css> ([0,0,1]),
		so it's [1,0,0],
		and the entire ''& c'' selector thus has specificity [1,0,1],
		which is larger than the specificity of ''.foo c'' ([0,1,1]).

		Notably, this is <em>different</em> than the result you'd get
		if the nesting were manually expanded out
		into non-nested rules,
		since the ''color: blue'' declaration would then be matching
		due to the ''b c'' selector ([0,0,2])
		rather than ''#a c'' ([1,0,1]).
	</div>

	<details class=note>
		<summary>Why is the specificity different than non-nested rules?</summary>

		The [=nesting selector=] intentionally uses the same specificity rules
		as the '':is()'' pseudoclass,
		which just uses the largest specificity among its arguments,
		rather than tracking <em>which</em> selector actually matched.

		This is required for performance reasons;
		if a selector has multiple possible specificities,
		depending on how precisely it was matched,
		it makes selector matching much more complicated and slower.

		That skirts the question, tho:
		why <em>do</em> we define ''&'' in terms of '':is()''?
		Some non-browser implementations of Nesting-like functionality
		do <em>not</em> desugar to '':is()'',
		largely because they predate the introduction of '':is()'' as well.
		Instead, they desugar directly;
		however, this comes with its own <em>significant</em> problems,
		as some (reasonably common) cases can accidentally produce <em>massive</em> selectors,
		due to the exponential explosion of possibilities.

		<pre class=lang-css>
		.a1, .a2, .a3 {
			.b1, .b2, .b3 {
				.c1, .c2, .c3 {
					...;
				}
			}
		}

		/* naively desugars to */
		.a1 .b1 .c1,
		.a1 .b1 .c2,
		.a1 .b1 .c3,
		.a1 .b2 .c1,
		.a1 .b2 .c2,
		.a1 .b2 .c3,
		.a1 .b3 .c1,
		.a1 .b3 .c2,
		.a1 .b3 .c3,
		.a2 .b1 .c1,
		.a2 .b1 .c2,
		.a2 .b1 .c3,
		.a2 .b2 .c1,
		.a2 .b2 .c2,
		.a2 .b2 .c3,
		.a2 .b3 .c1,
		.a2 .b3 .c2,
		.a2 .b3 .c3,
		.a3 .b1 .c1,
		.a3 .b1 .c2,
		.a3 .b1 .c3,
		.a3 .b2 .c1,
		.a3 .b2 .c2,
		.a3 .b2 .c3,
		.a3 .b3 .c1,
		.a3 .b3 .c2,
		.a3 .b3 .c3 {...}
		</pre>

		Here, three levels of nesting,
		each with three selectors in their lists,
		produced 27 desugared selectors.
		Adding more selectors to the lists,
		adding more levels of nesting,
		or making the nested rules more complex
		can make a relatively small rule
		expand into multiple megabytes of selectors
		(or much, much more!).

		Some CSS tools avoid the worst of this
		by heuristically discarding some variations,
		so they don't have to output as much
		but are still <em>probably</em> correct,
		but that's not an option available to UAs.

		Desugaring with '':is()'' instead eliminates this problem entirely,
		at the cost of making specificity slightly less useful,
		which was judged a reasonable trade-off.
	</details>

	The [=nesting selector=] is capable of matching [=featureless=] elements,
	if they were matched by the parent rule.

	While the position of a [=nesting selector=] in a [=compound selector=]
	does not make a difference in its behavior
	(that is, ''&amp;.foo'' and ''.foo&amp;'' match the same elements),
	the existing rule that a [=type selector=], if present, must be first in the [=compound selector=]
	continues to apply
	(that is, ''&amp;div'' is illegal, and must be written ''div&amp;'' instead).


<!-- Big Text: Nested Decl

█    █▌ █████▌  ███▌  █████▌ █████▌ ████▌      ████▌  █████▌  ███▌  █▌
█▌   █▌ █▌     █▌  █▌   █▌   █▌     █▌  █▌     █▌  █▌ █▌     █▌  █▌ █▌
██▌  █▌ █▌     █▌       █▌   █▌     █▌  █▌     █▌  █▌ █▌     █▌     █▌
█▌▐█ █▌ ████    ███▌    █▌   ████   █▌  █▌     █▌  █▌ ████   █▌     █▌
█▌  ██▌ █▌         █▌   █▌   █▌     █▌  █▌     █▌  █▌ █▌     █▌     █▌
█▌   █▌ █▌     █▌  █▌   █▌   █▌     █▌  █▌     █▌  █▌ █▌     █▌  █▌ █▌
█▌   ▐▌ █████▌  ███▌    █▌   █████▌ ████▌      ████▌  █████▌  ███▌  █████
-->

<h2 id=nested-declarations>
The Nested Declarations Rule</h2>

	For somewhat-technical reasons,
	it's important to be able to distinguish properties
	that appear at the start of a style rule's contents
	from those that appear interspersed with other rules.

	<div class=example>
		For example, in the following two rules:

		```css
		.foo {
			color: red;
			@media (...) {...}
			background: blue;
		}
		```

		We need to treat the ''color: red'' and ''background: blue'' slightly differently.
		In particular, in the CSSOM,
		the ''color: red'' is exposed in the style rule's {{CSSStyleRule/style}} attribute,
		while the ''background: blue'' needs to instead show up in its {{CSSGroupingRule/cssRules}} list.
	</div>

	To accomplish this, CSS parsing <em>automatically</em> wraps such properties
	in a special child rule
	to contain them.
	However, if we were to wrap them in a [=style rule=] with an ''&'' selector,
	it would have somewhat unfortunate behavior:

	<div class=example>
		For example, in

		```css
		.foo, .foo::before {
			color: red;
			& {
				background: blue;
			}
		}
		```

		the nested rule <em>does not</em> apply the 'background' property
		to the ''.foo::before'' elements,
		because the ''&'' can't represent pseudo-elements.
	</div>

	Similarly, child declarations in nested non-style rules
	need to be exposed as [=rules=] in some way,
	because these sorts of rules (like ''@media'')
	have never had {{CSSStyleRule/style}} properties.
	These run into the same problems as above.

	To address all of these issue,
	we instead wrap runs of consecutive directly-nested properties
	in a <dfn export>nested declarations rule</dfn>.

	Unless otherwise specified,
	a [=nested declarations rule=] is a [=nested style rule=],
	and acts identically to any other style rule.
	It matches the exact same elements and pseudo-elements
	as its parent style rule,
	with the same specificity behavior.
	<span class=note>(This is <em>similar to</em> being a style rule with an ''&'' selector,
	but slightly more powerful,
	as explained above.)</span>

	<details class=note>
		<summary>Why does the [=nested declarations rule=] exist?</summary>

		Originally, this specification grouped all declarations in style rules together,
		"moving" them from their original location
		to act as if they were placed at the front of the rule.
		It also automatically wrapped raw declarations inside of [=nested group rules=]
		in plain style rules,
		using the ''&'' selector.

		There are two major reasons we switched to instead use the [=nested declarations rule=].

		First, using an ''& {...}'' rule to implicitly wrap declarations in a [=nested group rule=]
		also changed the behavior.
		As shown in the example following this note,
		it breaks cases where the parent style rule contains pseudo-elements,
		and even when that's not the case,
		it potentially changes the specificity behavior of the nested declarations.
		Switching to the [=nested declarations rule=] avoids these problems,
		making the behavior of nested ''@media''/etc
		identical to the behavior of *non*-nested ''@media''/etc.

		Second, there are some details of future CSS features
		(notably, "mixins")
		that simply won't work correctly
		if interleaved declarations
		are automatically moved to the front of the style rule.
		We need to keep their relative order with other rules,
		and in order to actually make that representable in the CSSOM,
		that means they have to be wrapped in some kind of rule.
		The same issues as the previous paragraph apply if we just use a normal ''& {...}'' rule,
		so the [=nested declarations rule=] lets us do so without side effects.
	</details>

	<div class=example>
		For example, in the following stylesheet snippet:

		```css
		.foo, .foo::before, .foo::after {
			color: black;
			@media (prefers-color-scheme: dark) {
				& {
					color: white;
				}
			}
		}
		```

		In a darkmode page,
		the ''.foo'' element would have its text color changed to white,
		but its ''::before'' and ''::after'' pseudos would remain black,
		because the ''&'' selector can't represent pseudo-elements.

		However, it was instead written as:

		```css
		.foo, .foo::before, .foo::after {
			color: black;
			@media (prefers-color-scheme: dark) {
				color: white;
			}
		}
		```

		Then the ''color: white'' is implicitly wrapped in a [=nested declarations rule=],
		which is guaranteed to match <em>exactly</em> the same as its parent style rule,
		so the element <em>and</em> its pseudo-elements
		would all have white text in a darkmode page.
	</div>

	<div class=example>
		Declarations interleaved with rules get implicitly wrapped in a [=nested declarations rule=],
		which makes them part of a separate style rule.
		For example, given this CSS:

		```css
		.foo {
			color: black;
			@media (...) {...}
			background: silver;
		}
		```

		If the ''.foo'' rule's CSSOM object is examined,
		its {{CSSStyleRule/style}} attribute
		will contain only one declaration:
		the ''color: black'' one.

		The ''background: silver'' declaration
		will instead be found in the implicitly-created [=nested declarations rule|nested declarations child rule=],
		at <code highlight=js>fooRule.cssRules[1].style</code>.
	</div>





<!-- Big Text: cssom

 ███▌   ███▌   ███▌   ███▌  █     █
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ ██   ██
█▌     █▌     █▌     █▌  █▌ █▌█ █▐█
█▌      ███▌   ███▌  █▌  █▌ █▌ █ ▐█
█▌         █▌     █▌ █▌  █▌ █▌   ▐█
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ █▌   ▐█
 ███▌   ███▌   ███▌   ███▌  █▌   ▐█
-->

CSSOM {#cssom}
==============

Note: [[CSSOM-1]] now defines
that {{CSSStyleRule}} can have child rules.

When serializing a [=relative selector=] in a [=nested style rule=],
the selector must be absolutized,
with the implied [=nesting selector=] inserted.

<div class=example>
	For example, the selector ''> .foo''
	will serialize as ''& > .foo''.
</div>

The {{CSSNestedDeclarations}} Interface {#the-cssnestrule}
-----------------------------

The {{CSSNestedDeclarations}} interface represents a [=nested declarations rule=].

<xmp class=idl>
[Exposed=Window]
interface CSSNestedDeclarations : CSSRule {
	[SameObject, PutForwards=cssText] readonly attribute CSSStyleProperties style;
};
</xmp>

<div algorithm>
	The <dfn attribute for=CSSNestedDeclarations>style</dfn> attribute
	must return a {{CSSStyleProperties}} object for the rule,
	with the following properties:

	: [=CSSStyleDeclaration/computed flag=]
	:: Unset
	: [=CSSStyleDeclaration/readonly flag=]
	:: Unset
	: [=CSSStyleDeclaration/declarations=]
	:: The declared declarations in the rule, in [=specified order=].
	: [=CSSStyleDeclaration/parent CSS rule=]
	:: [=this=]
	: [=CSSStyleDeclaration/owner node=]
	:: Null
</div>

The {{CSSNestedDeclarations}} rule [=serialize a CSS rule|serializes=]
as if its [=CSS declaration block|declaration block=]
had been [=serialize a CSS declaration block|serialized=] directly.

Note: This means that multiple adjacent [=nested declarations rules=]
(which is possible to create with e.g. {{CSSGroupingRule/insertRule}})
will collapse into a single rule when serialized and parsed again.

<h2 class=no-num id=privacy>Privacy Considerations</h2>

No new privacy considerations have been reported on this specification.

<h2 class=no-num id=security>Security Considerations</h2>

No new security considerations have been reported on this specification.

<!-- Big Text: changes -->

<h2 id="changes">Changes</h2>

Significant changes since the
<a href="https://www.w3.org/TR/2023/WD-css-nesting-1-20230214/">Feb 14, 2023 Working Draft</a>:

* The <<scope-start>> selector of a ''@scope'' rule
	no longer acts as the parent rule for nesting.
	(<a href="https://github.com/w3c/csswg-drafts/issues/9740">Issue 9740</a>)

* Clarified that the [=nesting selector=] is allowed to match featureless elements.

* Switched ''&amp;div'' back to being invalid;
	now that Syntax does "infinite lookahead",
	we no longer need to allow it.
	Plus, doing so avoids a clash with preprocessors.
	(<a href="https://github.com/w3c/csswg-drafts/issues/8662">Issue 8662</a>)

* CSSOM now defines that CSSStyleRule is a CSSGroupingRule subclass,
	so the manual definition of the <code>cssRules</code> attribute and related machinery
	was removed.
	(<a href="https://github.com/w3c/csswg-drafts/issues/8940">Issue 8940</a>)

* Clarified the effect of the <em>implied</em> nesting selector on specificity.
	(<a href="https://github.com/w3c/csswg-drafts/issues/9069">Issue 9069</a>)

* Declarations intermixed with rules (or all declarations in nested group rules)
	are now automatically wrapped in <code>@nest</code> rules.
	(Also the <code>@nest</code> rule was added.)
	(<a href="https://github.com/w3c/csswg-drafts/issues/8738">Issue 8738</a>)

* Replaced <code>@nest</code> with [=nested declarations rules=].
	(<a href="https://github.com/w3c/csswg-drafts/issues/10234">Issue 10234</a>)
